#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "bubblefs.h"

FILE* fp;

int debug = 0;

void read_block(int bno, void* buf) {
        fseek(fp, BLOCKSIZE * bno, SEEK_SET);
        fread(buf, sizeof(char), BLOCKSIZE / sizeof(char), fp);
}

int main(int argc, char** argv) {
        char buf[BLOCKSIZE];
        if(argc != 2){
                fprintf(stderr, "Usage: fsinfo <fs name>\n");
                return 1;
        }

        char* path = argv[1];
        fp = fopen(path, "rb");
        if(fp < 0) {
                fprintf(stderr, "can not open %s\n", path);
                return 1;
        }
        read_block(0, buf);

        struct bubblefs_superblock* sb = (struct bubblefs_superblock*) buf;

        if(sb->magic != MAGICNUM) {
                fprintf(stderr, "invalid magic number %x\n", sb->magic);
                return 1;
        }

        printf("file system: %s\n", sb->name);
        printf("totoal size: %ld Bytes\n", sb->size);
        printf("total inode number: %d\n", sb->n_inodes);
        printf("total block number: %d\n", sb->n_blocks);
        
        char buf_new[BLOCKSIZE];
        uint64_t free = 0;

        for(int i=0; i<sb->n_inodes; i+=INODES_PER_BLOCK) {
                uint64_t bno = sb->inodes_offset + (i / INODES_PER_BLOCK);
                read_block(bno, buf_new);

                int number = INODES_PER_BLOCK;
                if((sb->n_inodes - i) < INODES_PER_BLOCK) {
                        number = sb->n_inodes - i;
                }

                for(int j=0; j<number; j++) {
                        struct bubblefs_inode* inode = ((struct bubblefs_inode*)buf_new) + j;
                        if(inode->used == 0) {
                                // found 
                                free++;
                        }else {
                                if(debug) {
                                        printf("inode name: %s\n", inode->name);
                                        for(int k=0; k<16; k++) {
                                                printf("        inode ref[%d].btype: %d\n",k , inode->refs[k].btype);
                                                printf("        inode ref[%d].offset: %d\n",k , inode->refs[k].offset);
                                        }
                                }
                        }
                }
        }

        printf("total free inode number: %ld\n", free);

        free = 0;
        for(int i=0; i<(sb->size / BLOCKSIZE); i+=BLOCKSIZE*8) {
                uint64_t bno = sb->free_map_offset + (i / BLOCKSIZE*8);
                read_block(bno, buf_new);

                int count = BLOCKSIZE*8;
                if(((sb->size / BLOCKSIZE) - i) < BLOCKSIZE*8) {
                        count = (sb->size / BLOCKSIZE) - i;
                }
                for(int j=0; j<count; j++) {
                        uint8_t mask = 1 << (j % 8);
                        uint8_t* free_map = (uint8_t*)buf_new;

                        if((free_map[j / 8] & mask) == 0) {
                                free++;
                        }
                }
        }

        printf("total free data block number: %ld\n", free);


        fclose(fp);

        return 0;
}
